package validjson;

import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.List;
import java.util.Map;


public class ValidatorFactoryImpl implements ValidatorFactory {
    public Validator createValidator(String uri) throws IOException, URISyntaxException {
        Schema schemaMap = new Schema(new URI(uri));
        return createValidator("object", schemaMap);
    }

    public Validator createValidator(Schema schema, Object value) throws IOException {
        Object propertyTypeObject = schema.getValue("type");
        if (propertyTypeObject instanceof String) {
            return createValidator((String) propertyTypeObject, schema);
        } else {
            return createValidator((List<String>) propertyTypeObject, value, schema);
        }
    }

    private Validator createValidator(String type, Schema schema) throws IOException {
        if ("string".equals(type)) {
            return new StringValidator(schema);
        } else if ("object".equals(type)) {
            return new ObjectValidator(schema, this);
        } else if ("boolean".equals(type)) {
            return new BooleanValidator();
        } else if ("number".equals(type)) {
            return new NumberValidator(schema);
        } else if ("integer".equals(type)) {
            return new IntegerValidator(schema);
        } else if ("array".equals(type)) {
            return new ArrayValidator(schema, this);
        } else if ("any".equals(type)) {
            return new AnyValidator();
        } else if ("null".equals(type)) {
            return new NullValidator();
        }

        throw new IllegalArgumentException("Unrecognised type '" + type + "'");
    }

    private Validator createValidator(List<String> types, Object value, Schema schema) throws IOException {
        for (String type : types) {
            if ("string".equals(type) && value instanceof String) {
                return new StringValidator(schema);
            } else if ("boolean".equals(type) && value instanceof Boolean) {
                return new BooleanValidator();
            } else if ("integer".equals(type) && value instanceof Integer) {
                return new IntegerValidator(schema);
            } else if ("number".equals(type) && value instanceof Number) {
                return new NumberValidator(schema);
            } else if ("array".equals(type) && value instanceof List) {
                return new ArrayValidator(schema, this);
            } else if ("object".equals(type) && value instanceof Map) {
                return new ObjectValidator(schema, this);
            }
        }

        for (String type : types) {
            if ("null".equals(type) && value == null) {
                return new NullValidator();
            }
        }

        for (String type : types) {
            if ("any".equals(type)) {
                return new AnyValidator();
            }
        }

        throw new IllegalArgumentException();
    }
}
